# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-07-15 23:10
# File     : yfinance_adapter.py
# Project  : dynamic-portfolio-optimizer
# Desc     :

import yfinance as yf
from typing import Dict, List, Any
import pandas as pd
from datetime import datetime
from .base_adapter import BaseDataAdapter, RateLimitDecorator


class YFinanceAdapter(BaseDataAdapter):
    """Yahoo Finance数据适配器"""

    def __init__(self, config):
        super().__init__(config)
        self.rate_limit = RateLimitDecorator(calls=10, period=1)

    @RateLimitDecorator(calls=10, period=1)
    def get_stock_data(self, symbol: str, start_date: datetime,
                       end_date: datetime, interval: str = '1d') -> pd.DataFrame:
        """获取股票数据"""
        try:
            ticker = yf.Ticker(symbol)
            data = ticker.history(
                start=start_date,
                end=end_date,
                interval=interval,
                auto_adjust=True,
                prepost=True
            )

            if data.empty:
                self.logger.warning(f"YFinance: 未获取到{symbol}的数据")
                return pd.DataFrame()

            # 添加数据源标识
            data['source'] = 'yfinance'
            data['symbol'] = symbol

            return self.standardize_data(data)

        except Exception as e:
            self.logger.error(f"YFinance获取股票数据失败: {e}")
            return pd.DataFrame()

    @RateLimitDecorator(calls=5, period=1)
    def get_options_data(self, symbol: str, expiration_date: datetime) -> pd.DataFrame:
        """获取期权数据"""
        try:
            ticker = yf.Ticker(symbol)
            options_dates = ticker.options

            if not options_dates:
                self.logger.warning(f"YFinance: {symbol}没有期权数据")
                return pd.DataFrame()

            # 找到最接近的到期日
            target_date = expiration_date.strftime('%Y-%m-%d')
            closest_date = min(options_dates, key=lambda x: abs(
                datetime.strptime(x, '%Y-%m-%d') - expiration_date
            ))

            option_chain = ticker.option_chain(closest_date)

            # 合并看涨和看跌期权
            calls = option_chain.calls.copy()
            calls['type'] = 'call'

            puts = option_chain.puts.copy()
            puts['type'] = 'put'

            options_data = pd.concat([calls, puts], ignore_index=True)
            options_data['symbol'] = symbol
            options_data['expiration'] = closest_date
            options_data['source'] = 'yfinance'

            return options_data

        except Exception as e:
            self.logger.error(f"YFinance获取期权数据失败: {e}")
            return pd.DataFrame()

    @RateLimitDecorator(calls=5, period=1)
    def get_fundamentals(self, symbol: str) -> Dict[str, Any]:
        """获取基本面数据"""
        try:
            ticker = yf.Ticker(symbol)
            info = ticker.info

            # 提取关键基本面指标
            fundamentals = {
                'symbol': symbol,
                'company_name': info.get('longName', ''),
                'sector': info.get('sector', ''),
                'industry': info.get('industry', ''),
                'market_cap': info.get('marketCap', 0),
                'pe_ratio': info.get('trailingPE', 0),
                'pb_ratio': info.get('priceToBook', 0),
                'dividend_yield': info.get('dividendYield', 0),
                'beta': info.get('beta', 0),
                'eps': info.get('trailingEps', 0),
                'revenue': info.get('totalRevenue', 0),
                'gross_margin': info.get('grossMargins', 0),
                'profit_margin': info.get('profitMargins', 0),
                'roe': info.get('returnOnEquity', 0),
                'debt_to_equity': info.get('debtToEquity', 0),
                'source': 'yfinance'
            }

            return fundamentals

        except Exception as e:
            self.logger.error(f"YFinance获取基本面数据失败: {e}")
            return {}

    @RateLimitDecorator(calls=5, period=1)
    def get_news(self, symbol: str, limit: int = 10) -> List[Dict[str, Any]]:
        """获取新闻数据"""
        try:
            ticker = yf.Ticker(symbol)
            news = ticker.news

            processed_news = []
            for item in news[:limit]:
                processed_news.append({
                    'symbol': symbol,
                    'title': item.get('title', ''),
                    'summary': item.get('summary', ''),
                    'url': item.get('link', ''),
                    'published_at': datetime.fromtimestamp(item.get('providerPublishTime', 0)),
                    'source': 'yfinance',
                    'provider': item.get('publisher', '')
                })

            return processed_news

        except Exception as e:
            self.logger.error(f"YFinance获取新闻数据失败: {e}")
            return []

# if __name__ == '__main__':
    # yfinance_adapter = YFinanceAdapter()
